// ID生成器: xf-序列号-最多4位随机数
class IdGen {
  constructor() {
    this.i = 0;
  }

  next() {
    this.i += 1;
    return this.i;
  }

  static _gen = new IdGen();
  static next() {
    return 'xf-'+IdGen._gen.next() + "-" + Math.floor(Math.random() * 10000);
  }
}

// 组件(对应界面左边的各种小组件)，所有组件都有列宽属性，用于控制col-*
class Widget {
  constructor(type) {
    this.type = type;
  }

  // 获取代码模板（拖放到设计器的时候要插入这段代码）
  get codeTemplate() {
    if (!this.type) return "EMPTY"; // _EMPTY
    return $(".code-template .frag-" + this.type).html();
  }

  // 获取属性设置Form（显示到右边的'字段'属性面板中）
  get propertyForm() {
    if (!this.type) return ""; // _EMPTY
    return $(".widget-properties .prop-" + this.type).html();
  }

  // 子类需要覆盖 updateUI 方法，更新DesignPanel中的组件UI
  updateUI(elm,name,value){
    console.log('updateUI', arguments)
    if('col'==name){
      this._updateCol(elm,value);
    }
    DesignPanel.get().update();
  }

  //更新组件所占的列宽（bootstrap默认为12列宽的栅格布局）
  _updateCol(elm,col){
    for(let i=1; i<=12; i++){
      elm.removeClass('col-' + i);
    }
    elm.addClass('col-' + col);
  }

  //获取所占列宽
  _getCol(elm){
    for(let i=1; i<=12; i++){
      if(elm.hasClass('col-' + i)){
        return i;
      }
    }
    //默认返回12
    return 12;
  }

  // 子类需要覆盖 props 方法，获取当前组件的所有属性
  props(elm){
    return {col: this._getCol(elm)};
  }

  static _EMPTY = new Widget();

  static of(type) {
    return Widget._allWidgets[type] || Widget._EMPTY;
  }
}

//bootstrap容器组件，可以设置子元素的默认列宽
class WidgetGrid extends Widget {
  constructor(type) {
    super(type || 'grid'); // 调用超类构造函数并传入name参数
  }

  addChild(gridElm, childElm){
    let p = this.props(gridElm);
    super.updateUI(childElm,col, p.defaultCol);
  }

  //注意gridElm参数，在向设计器添加第一个顶级Grid的时候，gridElm为空
  addChildType(gridElm, dropTargetElm, childWidgetType){
    let gridProps = gridElm ? this.props(gridElm) : {defaultCol:12};
    // console.log('grid props', gridProps);
    //赋值一个临时ID,继承GridElm的默认列宽
    let elm = $(`<div class='ui-state-default col-${gridProps.defaultCol}' data-id="${IdGen.next()}"></div>`).appendTo(dropTargetElm);
    elm.html(Widget.of(childWidgetType).codeTemplate);
    // 统一增加遮罩和删除按钮，点击后会显示出来
    if('grid'==childWidgetType){
      //容器类的组件不能用form-widget-mask的方式来处理，因为里面的小组件还要可以拖拽才行！！！
      if(gridElm){
        $(".layout-handler", elm).append(
          '<span class="badge badge-danger btn-delete my-2"><i class="bi-trash"></i></span>'
        );  
      }
    }else{
      $(".form-widget:first-child", elm).before(
        '<div class="form-widget-mask"><span class="badge badge-danger btn-delete"><i class="bi-trash"></i></span></div>'
      );
    }
    return elm;
  }

  // 子类需要覆盖 props 方法，获取当前组件的所有属性
  props(elm){
    let p = super.props(elm);
    p.defaultCol=elm.attr('data-default-col') || 12;
    return p;
  }

  updateUI(elm,name,value){
    super.updateUI(elm,name,value);
    if('defaultCol'==name){
      elm.attr('data-default-col',value*1);
      console.log('set defaultCol', value, 'get:', this.props(elm));
    }
  }

}

class WidgetInput extends Widget {
  constructor(type) {
    super(type || 'input'); // 调用超类构造函数并传入name参数
  }

  updateUI(elm,name,value){
    console.log('widget [input] updateUI',arguments);
    if('label'==name){
      $('label',elm).html(value);
    }else if('placeholder'==name){
      this.coreElm(elm).attr('placeholder',value);
    }
    super.updateUI(elm,name,value);
  }

  //返回Input组件的核心元素<input> or <textarea>
  coreElm(elm){
    return $(`${this.type}.form-control`,elm);
  }

  props(elm){
    let p = super.props(elm);
    p.label = $('label',elm).html();
    p.placeholder=this.coreElm(elm).attr('placeholder');
    return p;
  }

}

class WidgetTextArea extends WidgetInput {
  constructor(type) {
    super(type || 'textarea'); // 调用超类构造函数并传入name参数
  }

  updateUI(elm,name,value){
    let ce = this.coreElm(elm);
    if('rows'==name){
      ce.attr('rows',value);
    }
    super.updateUI(elm,name,value);
  }

  props(elm){
    let p = super.props(elm);
    let ce = this.coreElm(elm);
    p.rows=ce.attr('rows');
    return p;
  }
}

Widget._allWidgets = {
  input: new WidgetInput(),
  textarea: new WidgetTextArea(),
  grid: new WidgetGrid(),
};


// 表单元素, 即是某一个Widget拖拽到画布上的实例
class FormItem {
  constructor(type,id) {
    this.type = type;
    this.id = id;
  }

  get widget() {
    return Widget.of(this.type);
  }
}

// 中间的预览
class Previewer {
  constructor(designPanel, selector) {
    this.designPanel = designPanel;
    this.elm = $(selector);
  }

  update(html) {
    this.elm.html(html);
  }
}

// 中间的代码
class Coder {
  constructor(designPanel, selector) {
    this.designPanel = designPanel;
    this.elm = $(selector);
  }

  update(html) {
    this.elm.html(html);
  }
}

// 中间的设计器
class Designer {
  constructor(designPanel, selector) {
    this.designPanel = designPanel;
    this.elm = $(selector);
  }

  //拖拽增加一个组件
  dragTo(target, dragger, event) {
    console.log('target:', target, 'arguments:',arguments);
    let widgetType = dragger.draggable.data("type"); // widget type
    let gridElm = $(target).parent().parent();
    let childElm = Widget.of('grid').addChildType(gridElm, target,widgetType);
    this.bindWidgetEvent(childElm);
    makeDroppable($('.widget-form-list',childElm));

    this.designPanel.update();
    //拖拽过来以后，默认选中
    this.onClick(childElm);
  }

  // 设计区域选择了一个组件，需要在右边显示对应的属性
  onClick(target) {
    target=$(target);
    console.log('click',target);
    if (this.lastMask) {
      this.lastMask.removeClass("active");
    }

    let mask = $(".form-widget-mask", target);
    mask.addClass("active");
    this.lastMask = mask;
    // 属性面板需要load一下
    PropertyPanel.load(target);
  }

  // 设计区域点击了删除按钮
  onDelete(target) {
    if (this.lastMask) {
      this.lastMask = false;
    }
    target.remove();
    this.designPanel.update();
  }

  // 设计区域拖拽了一个新组件进来以后，需要绑定选取事件
  bindWidgetEvent(target) {
    let that = this;
    //绑定点击事件
    $(".form-widget-mask, .layout-handler", target).click(function (e) {
      that.onClick(target);
      e.stopPropagation();
    });
    
    //绑定删除按钮
    $(".form-widget-mask .btn-delete, .layout-handler .btn-delete", target).click(function (e) {
      that.onDelete(target);
      e.stopPropagation();
    });

    //可以排序，排序结束做一下更新
    $('.widget-form-list').sortable({
      start:(event,ui)=>that.onClick(ui.item[0]),
      stop:()=>that.designPanel.update() // 不能用change, change会导致出来的位置不准，因为还没有stop，没有停留到合适的位置
    });
  }

  get html() {
    let elm = $("#design-form").clone();
    //需要删除多余的遮罩元素
    $(".form-widget-mask, .layout-handler", elm).remove();

    //删除多余的样式，主要是拖拽组件附加上的各种样式
    $(['ui-state-default','ui-sortable-handle','ui-sortable','ui-droppable']).each((i,cls)=>{
      $("."+cls, elm).removeClass(cls);
    });
    
    let html = elm[0].outerHTML;
    return html;
  }

  static get() {
    return DesignPanel.get().designer;
  }

  static dragTo(target, dragger, event) {
    Designer.get().dragTo(target, dragger, event);
  }
}

// 中间的设计面板，包括：设计器，预览区，代码
class DesignPanel {
  constructor(selector) {
    this.elm = $(selector);
    this.designer = new Designer(this, $("#widget-form-container", this.elm));
    this.previewer = new Previewer(this, $("#preview-body", this.elm));
    this.coder = new Coder(this, $("#code-textarea", this.elm));
  }

  update() {
    setTimeout(() => {
      let html = this.designer.html;
      this.previewer.update(html);
      this.coder.update(html);
    }, 300);
  }

  static _panel = new DesignPanel("#design-panel");

  static get() {
    return DesignPanel._panel;
  }
}

class PropertyPanel {
  
  static load(elm){
    let widgetType = $(".form-widget", elm).data("type");
    let widget = Widget.of(widgetType);
    PropertyPanel._elm = elm;
    PropertyPanel._widget = widget;

    //加载属性Form
    $("#prop-tab-panel-field").html(widget.propertyForm);
    let props = widget.props(elm);
    // console.log('widget props:', props);

    //设置各个属性值
    $('#prop-tab-panel-field .form-control').each((i,e)=>{
      e = $(e);
      let name = e.data('field')
      e.val(props[name]);
    });

    $('#prop-tab-panel-field .form-control').keyup(function(event){
      let e = $(event.target);
      let name = e.data('field')
      widget.updateUI(elm,name,e.val());
    });
  }

  static _elm ;
  static _widget ;


  static all() {
    let p = {};
    $('#prop-tab-panel-field .form-control').each((i,elm)=>{
      elm = $(elm);
      p[elm.data('field')]=elm.val();
    });
    return p;
  }
}

function onWindowResize() {
  //调整设计区域大小
  let parentTop = $("#design-panel .tab-content").offset().top;
  let winHeight = $(window).height();
  let clientHeight = winHeight - parentTop - 10;
  $(".widget-form-container").height(clientHeight);
  $("#code-textarea").height(clientHeight);
  $("#preview-body").height(clientHeight);
}

let body = $(document).find("body");

//设置为可拖放的区域
function makeDroppable(selector){
  $(selector).droppable({
    accept: ".form-edit-widget-label",
    greedy: true,
    classes: {
      "ui-droppable-hover": "ui-state-hover",
    },
    drop: function (event, ui) {
      Designer.dragTo($(this), ui, event);
    },
  });
}

// 页面加载以后的功能初始化
(function () {
  "use strict";

  // 左边组件区域的拖拽事件
  $(".components-list .form-edit-widget-label").draggable({
    // helper: "clone",
    containment: "window",
    cursor: "move",
    helper: function (event) {
      let target = $(this).clone();
      $(target).addClass("dragging-widget");
      target.appendTo(body);
      return target;
    },
    revert: "invalid",
  });


  //调整设计区域大小
  onWindowResize();
  $(window).resize(function () {
    onWindowResize();
  });

  //默认向设计区增加一个顶级的Grid组件
  setTimeout(()=>{
    let topGrid = Widget.of('grid').addChildType(undefined, $("#design-form"),'grid');
    // 中间设计区域的拖放事件
    makeDroppable('.widget-form-list');
    Designer.get().bindWidgetEvent(topGrid);
  },500)
  
})();
